package com.portal.settings;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 设置
 *
 * @author Amadeus
 * @date 2025/02/26
 */
@Slf4j
public class Settings {

    /**
     * 未定义的值，这个值一般只会在第一次出现
     */
    public static final String UNDEFINED_CONTENT = "MS_UD_C";

    /**
     * 是否开启配置中心，默认开启
     */
    @Getter
    @Setter
    private static Boolean enable;

    /**
     * 所有配置行数据
     */
    private static List<SettingsRow> settingsRows = new ArrayList<>();

    /**
     * 注册回调，单个配置项
     */
    private static ListValuedMap<Pair<String, String>, Function<SettingsRow, Integer>> CALLBACK_MAP = new ArrayListValuedHashMap<>();

    /**
     * 注册回调，全量配置项
     */
    private static List<SettingsPullCallback> SETTINGS_PULL_CALLBACKS = new ArrayList<>();

    public static List<SettingsRow> getSettingsRows() {
        return settingsRows;
    }

    /**
     * 注册单个配置的监听器，线程安全
     *
     * @param name     name
     * @param group    group
     * @param function 回调函数 返回值为影响配置数量，一般为0或1
     */
    public synchronized static void registerRowListener(String name, String group, Function<SettingsRow, Integer> function) {
        if (StringUtils.isAnyBlank(name, group) || function == null) {
            return;
        }
        ListValuedMap<Pair<String, String>, Function<SettingsRow, Integer>> newCallbackMap = new ArrayListValuedHashMap<>(CALLBACK_MAP);
        newCallbackMap.put(Pair.of(name, group), function);
        CALLBACK_MAP = newCallbackMap;
    }

    /**
     * 注册全部配置的监听器，线程安全
     *
     * @param settingsPullCallback name
     */
    public synchronized static void registerCallback(Collection<SettingsPullCallback> settingsPullCallback) {
        if (settingsPullCallback == null) {
            return;
        }
        List<SettingsPullCallback> settingsPullCallbacks = new ArrayList<>(SETTINGS_PULL_CALLBACKS);
        settingsPullCallbacks.addAll(settingsPullCallback);
        SETTINGS_PULL_CALLBACKS = settingsPullCallbacks;
    }

    /**
     * 合并增量配置并且回调注册的观察者
     *
     * @param deltaSettingsRows 增量配置
     * @return 影响的配置数量
     */
    static int mergeDeltaRowsAndCallback(List<SettingsRow> deltaSettingsRows) {
        mergeDeltaRows(deltaSettingsRows);
        // 注意：这里即便没有配置更新，也会走一遍所有配置的检查、赋值，防止有人在代码中修改配置
        // 先回调注册的单个配置
        int effectTotal = Settings.callForRegisteredRowListener();
        // 再全量回调配置
        Settings.callForRegisteredAllCallback();

        return effectTotal;
    }

    /**
     * 合并增量配置到全部配置里面
     */
    private static void mergeDeltaRows(List<SettingsRow> deltaSettingsRows) {
        // 合并增量的到全量的里面
        if (deltaSettingsRows != null && !deltaSettingsRows.isEmpty()) {
            Map<String, SettingsRow> settingsRowMap = Settings.settingsRows.stream().collect(Collectors.toMap(SettingsRow::getUniqueKey, item -> item));
            for (SettingsRow deltaRow : deltaSettingsRows) {
                settingsRowMap.put(deltaRow.getUniqueKey(), deltaRow);
            }
            Settings.settingsRows = new ArrayList<>(settingsRowMap.values());
        }
    }

    private static int callForRegisteredRowListener() {
        if (settingsRows == null || settingsRows.isEmpty()) {
            return 0;
        }

        int[] effectTotal = new int[]{0};
        settingsRows.forEach(item -> {
            List<Function<SettingsRow, Integer>> consumerList = CALLBACK_MAP.get(Pair.of(item.getName(), item.getGroup()));
            if (consumerList != null && !consumerList.isEmpty()) {
                for (Function<SettingsRow, Integer> function : consumerList) {
                    try {
                        Integer effectRow = function.apply(item);
                        if (effectRow != null && effectRow > 0) {
                            effectTotal[0] = effectTotal[0] + effectRow;
                        }
                    } catch (Throwable t) {
                        log.error("Settings Config Callback Exception", t);
                    }
                }
            }
        });
        return effectTotal[0];
    }

    private static void callForRegisteredAllCallback() {
        for (SettingsPullCallback settingsPullCallback : SETTINGS_PULL_CALLBACKS) {
            try {
                settingsPullCallback.accept(Settings.settingsRows);
            } catch (Throwable t) {
                log.error("配置回调失败", t);
            }
        }
    }

    @Getter
    @Setter
    public static class SettingsRow {
        /**
         * 配置ID
         */
        private String id;
        /**
         * 配置名称，最大64个字符
         */
        private String name;
        /**
         * 分组，自定义，可以是模块等，最大64个字符
         */
        private String group;
        /**
         * 配置内容，JSON格式，最大4096字符
         */
        private String content;
        /**
         * 修改时间，精度为微秒
         */
        private Date gmtModified;
        /**
         * 描述，最大255个字符
         */
        private String description;

        /**
         * 虚拟区域
         */
        private String virtualRegion;

        /**
         * 租户id
         */
        private Long tenantId;

        public String getUniqueKey() {
            return getTenantId() + "::" + getVirtualRegion() + "::" + getGroup() + "::" + getName();
        }
    }

}
